
/** 
 * Copyright 2014 NAVER Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.*/

package com.ideal.ete.collector.controller;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.hadoop.hbase.client.Scan;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.client.RestTemplate;

import com.alibaba.fastjson.JSON;
import com.ideal.ete.collector.application.CenterInfo;
import com.ideal.ete.collector.applicationMap.ApplicationMap;
import com.ideal.ete.collector.calltree.span.CallTreeIterator;
import com.ideal.ete.collector.dao.AgentInfoDao;
import com.ideal.ete.collector.dao.CenterInfoDao;
import com.ideal.ete.collector.dao.TraceDao;
import com.ideal.ete.collector.hbase.HBaseTables;
import com.ideal.ete.collector.ppLook.TreeNode;
import com.ideal.ete.collector.server.bo.SpanBo;
import com.ideal.ete.collector.server.bo.StringMetaDataBo;
import com.ideal.ete.collector.service.CenterInfoService;
import com.ideal.ete.collector.service.FilteredMapService;
import com.ideal.ete.collector.service.SpanResult;
import com.ideal.ete.collector.service.SpanService;
import com.ideal.ete.collector.service.TransactionInfoService;
import com.ideal.ete.collector.utils.TransactionId;
import com.ideal.ete.collector.utils.TransactionIdUtils;
import com.ideal.ete.collector.view.TransactionInfoViewModel;
import com.ideal.ete.collector.vo.AgentInfo;
import com.ideal.ete.collector.vo.LimitedScanResult;
import com.ideal.ete.collector.vo.Range;
import com.ideal.ete.collector.vo.RecordSet;
import com.ideal.hbase.client.HbaseOperations;
import com.ideal.hbase.client.core.mapper.RowMapper;

/**
 * @author emeroad
 * @author jaehong.kim
 */
@Controller
public class BusinessTransactionController {

	private Logger logger = LoggerFactory.getLogger(this.getClass());

	@Value("${server.port:2182}")
	private String port;

	private RestTemplate rs = new RestTemplate();

	@Autowired
	private HbaseOperations hbaseOperations2;

	@Autowired
	private TraceDao hbaseTraceDaoV2;
	
	   @Autowired
	    private CenterInfoService centerInfoService;
	
	

	@Autowired
	private AgentInfoDao agentInfoDao;
	
	@Autowired
	private CenterInfoDao centerInfoDao;

	@Autowired
	@Qualifier("agentInfoMapper")
	private RowMapper<AgentInfo> agentInfoMapper;

	@Autowired
	@Qualifier("stringMetaDataMapper")
	private RowMapper<List<StringMetaDataBo>> stringMetaDataMapper;

	@Autowired
	private SpanService spanService;

	@Autowired
	private TransactionInfoService transactionInfoService;

	@Autowired
	private FilteredMapService filteredMapService;

	@Value("#{pinpointWebProps['log.enable'] ?: false}")
	private boolean logLinkEnable;

	@Value("#{pinpointWebProps['log.button.name'] ?: ''}")
	private String logButtonName;

	@Value("#{pinpointWebProps['log.page.url'] ?: ''}")
	private String logPageUrl;

	@Value("#{pinpointWebProps['log.button.disable.message'] ?: ''}")
	private String disableButtonMessage;

	private final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss S");

	/**
	 * info lookup for a selected transaction
	 *
	 * @param traceIdParam
	 * @param focusTimestamp
	 * @return
	 */
	@RequestMapping(value = "/getAgentInfoByTimeScope", method = RequestMethod.GET)
	@ResponseBody
	public Object getAgentInfoByTimeScope(
			@RequestParam("center") String center,
			@RequestParam("startTimestamp") long startTimestamp,
			@RequestParam("endTimestamp") long endTimestamp,
			@RequestParam("limit") int limit) {

		// Scan scan = new Scan();
		// scan.setCaching(30);
		// List<AgentInfo> results = hbaseOperations2.find(
		// HBaseTables.AGENTINFO, scan, agentInfoMapper);
		// List<AgentInfo> agentInfoList = new ArrayList<>();
		// System.out.println("---------------");
		// for (AgentInfo result : results) {
		// if(result.getStartTimestamp() > startTimestamp &&
		// result.getStartTimestamp()< endTimestamp ){
		// System.out.println(result);
		// agentInfoList.add(result);
		// }
		//
		// }
		// Object json = JSON.toJSON(agentInfoList);
		// return json;
		Scan scan = new Scan();
		scan.setCaching(30);
		List<List<StringMetaDataBo>> results = hbaseOperations2.find(HBaseTables.STRING_METADATA, scan,
				stringMetaDataMapper);
		List<StringMetaDataBo> children = new ArrayList<>();
		List<AgentInfo> agentInfo = new ArrayList<>();
		Set set = new HashSet();
		for (List<StringMetaDataBo> result : results) {
			for (StringMetaDataBo stringMetaDataBo : result) {

				if (stringMetaDataBo.getStringValue().contains("Exception")
						&& stringMetaDataBo.getStartTime() > startTimestamp
						&& stringMetaDataBo.getStartTime() < endTimestamp) {
					AgentInfo initialAgentInfo = agentInfoDao.getInitialAgentInfo(stringMetaDataBo.getAgentId());
					set.add(initialAgentInfo);
					children.addAll(result);
				}
			}

		}

		Map<String, Object> map = new HashMap<>();
		map.put("StringMetaData", children);
		map.put("AgentInfoList", set);

		Object json = JSON.toJSON(map);

		return json;

	}
	
	
	@RequestMapping(value = "/getAgentInfoByTimeScope1", method = RequestMethod.GET)
	@ResponseBody
	public Object getAgentInfoByTimeScope1(
			@RequestParam("center") String center,
			@RequestParam("startTimestamp") long startTimestamp,
			@RequestParam("endTimestamp") long endTimestamp,
			@RequestParam("limit") int limit) {

		
		Scan scan = new Scan();
		scan.setCaching(30);
		List<List<StringMetaDataBo>> results = hbaseOperations2.find(HBaseTables.STRING_METADATA, scan,
				stringMetaDataMapper);
		List<CenterInfo> allCenterInfos = centerInfoDao.getCenterInfosByCenter(center);
		List<StringMetaDataBo> children = new ArrayList<>();
//		List<CenterInfo> centerInfo = new ArrayList<>();
		Set<CenterInfo> set = new HashSet<CenterInfo>();
		Map<String,Object> map = new HashMap<>();
		for (List<StringMetaDataBo> result : results) {
			for (StringMetaDataBo stringMetaDataBo : result) {

				if (stringMetaDataBo.getStringValue().contains("Exception")
						&& stringMetaDataBo.getStartTime() > startTimestamp
						&& stringMetaDataBo.getStartTime() < endTimestamp) {
					for (CenterInfo centerInfo : allCenterInfos) {
						if(stringMetaDataBo.getAgentId().equals(centerInfo.getAgentId())){
							CenterInfo initialCenterInfo = centerInfoDao.getAgentInfoByAgentId(stringMetaDataBo.getAgentId(), center);
							set.add(initialCenterInfo);
							map.put(initialCenterInfo.getAgentId(), initialCenterInfo);
							
							if(children.size() != 0){
								boolean flag = true;
								for (StringMetaDataBo stringMetaData : children) {
									if(stringMetaData.getAgentId().equals(stringMetaDataBo.getAgentId())){
										flag = false;
									}
								}
								if(flag){
									children.add(stringMetaDataBo);
								}
							}else{
								children.add(stringMetaDataBo);
							}
							
						}
					}
					
					
				}
			}

		}

		Map<String, Object> data = new HashMap<>();
		data.put("StringMetaData", children);
		data.put("CenterInfoList", set);

		Object json = JSON.toJSON(data);

		return json;

	}
	@RequestMapping(value = "/getAgentInfoByTimeScope2", method = RequestMethod.GET)
	@ResponseBody
	public Object getAgentInfoByTimeScope2(
			@RequestParam("center") String center,
			@RequestParam("startTimestamp") long startTimestamp,
			@RequestParam("endTimestamp") long endTimestamp,
			@RequestParam("limit") int limit) {
		
		
		Scan scan = new Scan();
		scan.setCaching(30);
		List<List<StringMetaDataBo>> results = hbaseOperations2.find(HBaseTables.STRING_METADATA, scan,
				stringMetaDataMapper);
		List<CenterInfo> allCenterInfos = centerInfoDao.getAllCenterInfos();
		List<StringMetaDataBo> children = new ArrayList<>();
//		List<CenterInfo> centerInfo = new ArrayList<>();
		Set<CenterInfo> set = new HashSet<CenterInfo>();
		Map<String,Object> map = new HashMap<>();
		for (List<StringMetaDataBo> result : results) {
			for (StringMetaDataBo stringMetaDataBo : result) {
				
				if (stringMetaDataBo.getStringValue().contains("Exception")
						&& stringMetaDataBo.getStartTime() > startTimestamp
						&& stringMetaDataBo.getStartTime() < endTimestamp) {
					for (CenterInfo centerInfo : allCenterInfos) {
						if(stringMetaDataBo.getAgentId().equals(centerInfo.getAgentId())){
//							CenterInfo initialCenterInfo = centerInfoDao.getAgentInfoByAgentId(stringMetaDataBo.getAgentId(), center);
							set.add(centerInfo);
//							map.put(initialCenterInfo.getAgentId(), initialCenterInfo);
							
							if(children.size() != 0){
								boolean flag = true;
								for (StringMetaDataBo stringMetaData : children) {
									if(stringMetaData.getAgentId().equals(stringMetaDataBo.getAgentId())){
										flag = false;
									}
								}
								if(flag){
									children.add(stringMetaDataBo);
								}
							}else{
								children.add(stringMetaDataBo);
							}
							
						}
					}
					
					
				}
			}
			
		}
		
		Map<String, Object> data = new HashMap<>();
		data.put("StringMetaData", children);
		data.put("CenterInfoList", set);
		
		Object json = JSON.toJSON(data);
		
		return json;
		
	}

	@RequestMapping(value = "/showAgentInfo", method = RequestMethod.GET)
	@ResponseBody
	public Object showAgentInfo(@RequestParam("applicationName") String applicationName,
			@RequestParam(value = "startTimestamp", required = false, defaultValue = "0") long startTimestamp,
			@RequestParam(value = "endTimestamp", required = false, defaultValue = "0") long endTimestamp,
			@RequestParam(value = "limit", required = false, defaultValue = "1000") int limit) {

		Range range = new Range(startTimestamp, endTimestamp);
		LimitedScanResult<List<TransactionId>> limitedScanResult = filteredMapService
				.selectTraceIdsFromApplicationTraceIndex(applicationName, range, limit);
		List<TransactionId> tranIdList = limitedScanResult.getScanData();
		List<List<SpanBo>> traceList = hbaseTraceDaoV2.selectSpans(tranIdList);
		List<String> agentIds = new ArrayList<>();
		for (List<SpanBo> trace : traceList) {
			for (SpanBo spanBo : trace) {
				if (applicationName.equals(spanBo.getApplicationId())) {
					agentIds.add(spanBo.getAgentId());
				}
			}
		}
		List<AgentInfo> initialAgentInfos = agentInfoDao.getInitialAgentInfos(agentIds);
		return JSON.toJSON(new HashSet(initialAgentInfos));

	}

	@RequestMapping(value = "/exceptionList", method = RequestMethod.GET)
	@ResponseBody
	public Object exceptionList(@RequestParam("startTimestamp") long startTimestamp,
			@RequestParam("endTimestamp") long endTimestamp, @RequestParam("agentId") String agentId) {

		AgentInfo initialAgentInfo = agentInfoDao.getInitialAgentInfo(agentId);

		String applicationName = initialAgentInfo.getApplicationName();

		Range range = new Range(startTimestamp, endTimestamp);
		LimitedScanResult<List<TransactionId>> limitedScanResult = filteredMapService
				.selectTraceIdsFromApplicationTraceIndex(applicationName, range, 10000);
		List<TransactionId> tranIdList = limitedScanResult.getScanData();
		List<List<SpanBo>> traceList = hbaseTraceDaoV2.selectSpans(tranIdList);
		List<SpanBo> spanBoList = new ArrayList<>();
		for (List<SpanBo> trace : traceList) {
			for (SpanBo spanBo : trace) {
				if (applicationName.equals(spanBo.getApplicationId())) {
					spanBoList.add(spanBo);
				}
				if (spanBoList.size() == 1000) {
					break;
				}
			}
		}
//		System.out.println(spanBoList.toString());
		return spanBoList;

		// Object json = JSON.toJSON(initialAgentInfo);
		// return json;

	}

	@RequestMapping(value = "/transactionInfo", method = RequestMethod.GET)
	@ResponseBody
	public TransactionInfoViewModel transactionInfo(@RequestParam("traceId") String traceIdParam,
			@RequestParam(value = "focusTimestamp", required = false, defaultValue = "0") long focusTimestamp,
			@RequestParam(value = "agentId", required = false) String agentId,
			@RequestParam(value = "spanId", required = false, defaultValue = "-1") long spanId,
			@RequestParam(value = "v", required = false, defaultValue = "0") int viewVersion) {
		logger.debug("GET /transactionInfo params {traceId={}, focusTimestamp={}, agentId={}, spanId={}, v={}}",
				traceIdParam, focusTimestamp, agentId, spanId, viewVersion);

		final TransactionId transactionId = TransactionIdUtils.parseTransactionId(traceIdParam);

		// select spans
		final SpanResult spanResult = this.spanService.selectSpan(transactionId, focusTimestamp);
		final CallTreeIterator callTreeIterator = spanResult.getCallTree();

		// application map
		ApplicationMap map = filteredMapService.selectApplicationMap(transactionId);
		RecordSet recordSet = this.transactionInfoService.createRecordSet(callTreeIterator, focusTimestamp, agentId,
				spanId);

		TransactionInfoViewModel result = new TransactionInfoViewModel(transactionId, map.getNodes(), map.getLinks(),
				recordSet, spanResult.getCompleteTypeString(), logLinkEnable, logButtonName, logPageUrl,
				disableButtonMessage);
		return result;
	}

	@RequestMapping(value = "/transactionInfoDetail2", method = RequestMethod.GET)
	@ResponseBody
	public String transactionInfoDetail2(@RequestParam("traceId") String traceIdParam,
			@RequestParam(value = "focusTimestamp", required = false, defaultValue = "0") long focusTimestamp,
			@RequestParam(value = "agentId", required = false) String agentId,
			@RequestParam(value = "spanId", required = false, defaultValue = "-1") long spanId,
			@RequestParam(value = "mRpc", required = false, defaultValue = "notFound") String mRpc) {

		Map<String, Object> model = rs.getForObject("http://10.145.196.107:38080/transactionInfo.pinpoint?traceId="
				+ traceIdParam + "&agentId=" + agentId + "&spanId=" + spanId + "&focusTimestamp=" + focusTimestamp,
				Map.class);

		List<List<Object>> callStack = (List<List<Object>>) model.get("callStack");

		if (CollectionUtils.isEmpty(callStack)) {
			return "";
		}
		// System.out.println(callStack);
		TreeNode treeNode = recursiveTree2(callStack, callStack.get(0).get(6).toString(), mRpc);

		List<TreeNode> rsList = new ArrayList<>();
		rsList.add(treeNode);

		Map<String, Object> map = new HashMap<>();
		map.put("rsList", rsList);
		String str = JSON.toJSONString(map);
		return str;
	}

	private TreeNode recursiveTree2(List<List<Object>> list, String tid, String mRpc) {
		TreeNode tn = new TreeNode();
		List<String> tags = new ArrayList<>();
		List<List<Object>> childList = new ArrayList<>();
		// System.out.println(list);
		for (List<Object> cList : list) {
			if (tid.equals(cList.get(6).toString())) {
				if (cList.get(4) == null) {
					tn.setTags(null);
					tn.setText(cList.get(10) + "");
					tn.setIcon("glyphicon glyphicon-info-sign");
					continue;
				} else {
					tn.setText(cList.get(10) + " (" + cList.get(11) + ")");
					tags.add(transferLongToDate(sdf, (long) cList.get(1)));
					tags.add(cList.get(14) + "ms");
					tags.add(cList.get(20) + " (" + cList.get(4) + ")");
					tags.add("方法名: " + cList.get(17) + " (" + cList.get(19) + ")");
					tn.setTags(tags);
				}
				if ("Tomcat Servlet Process".equals(cList.get(10).toString())) {
					tn.setIcon("glyphicon glyphicon-cloud");
					if (mRpc.equals(cList.get(11).toString())) {
						tn.setColor("#428bca");
						tn.setBackColor("#9eff7c");
					}
				}

				continue;
			}
			if (tid.equals(cList.get(7).toString())) {

				if (cList.get(10).toString().indexOf("Exception") != -1) {

					tn.setColor("#428bca");
					tn.setBackColor("#FFD2D2");

				}

				childList.add(cList);
			}

		}
		for (List<Object> child : childList) {
			TreeNode rl = recursiveTree2(list, child.get(6).toString(), mRpc);
			tn.getNodes().add(rl);
		}
		if (CollectionUtils.isEmpty(tn.getNodes())) {
			tn.setNodes(null);
		}
		return tn;
	}
	
	 public String getCenterByApplicationName(String applicationName) {
	    	
	    	List<CenterInfo> centerList = centerInfoService.getAllCenterInfos();
	    	String centerName = null;
	    	String center = null;
	    	long timestamp = 0;
	    	for (CenterInfo centerInfo : centerList) {
				if(applicationName.equals(centerInfo.getApplicationType().getApplicationName())){
					if(centerInfo.getTimeStamp() > timestamp){
						center = centerInfo.getCenter();
						timestamp = centerInfo.getTimeStamp();
					}
					
				}
			}
	    	
	    	if(center.equals("ordercenter")){
				centerName = "受理引擎";
			}else if(center.equals("custcenter")){
				centerName = "客户引擎";
			}else if(center.equals("cpccenter")){
				centerName = "CPC配置引擎";
			}else if(center.equals("msc")){
				centerName = "营服协同引擎";
			}else{
				centerName = "未知引擎";
			}
	    	
	    	
	    	return centerName;
	    }
	 
	

	private TreeNode recursiveTree4(List<List<Object>> list, String tid, String mRpc) {
		TreeNode tn = new TreeNode();
		List<String> tags = new ArrayList<>();
		List<List<Object>> childList = new ArrayList<>();
//		 System.out.println(list);
		for (List<Object> cList : list) {
			if (tid.equals(cList.get(6).toString())) {
				if (cList.get(4) == null) {
					tn.setTags(null);
					tn.setText(cList.get(10) + "");
					tn.setIcon("glyphicon glyphicon-info-sign");
					continue;
				} else {
					String str = (String) cList.get(11);
					str = str.substring(1);
					String[] split = str.split("/");
					String text = "";
					if (split.length == 4) {
						text = getCenterByApplicationName(cList.get(4).toString()) + "  --- " + cList.get(4) + " (服务)";
						tn.setText(text);
					} else {
						tn.setText(cList.get(11) + "");
					}

					tags.add(transferLongToDate(sdf, (long)cList.get(1)));
//					long a = (long)cList.get(2) - (long)cList.get(1);
					tags.add("self all : " + cList.get(14) + " ms");
					if(!"".equals(cList.get(7))){
						tags.add("上层 -- self : " + cList.get(15) + " ms");
					}
					
					
					

					tn.setTags(tags);
				}
				if ("Tomcat Servlet Process".equals(cList.get(10).toString())) {

					if (mRpc.equals(cList.get(11).toString())) {
						tn.setColor("#428bca");
						tn.setBackColor("#9eff7c");
					}
				}

				continue;
			}
			if (tid.equals(cList.get(7).toString())) {

				childList.add(cList);
			}

		}
		for (List<Object> child : childList) {
			TreeNode rl = recursiveTree4(list, child.get(6).toString(), mRpc);
			tn.getNodes().add(rl);
		}
		if (CollectionUtils.isEmpty(tn.getNodes())) {
			tn.setNodes(null);
		}
		return tn;
	}

	@RequestMapping(value = "/transactionInfoDetail", method = RequestMethod.GET)
	@ResponseBody
	public Object transactionInfoDetail(@RequestParam("traceId") String traceIdParam,
			@RequestParam(value = "focusTimestamp", required = false, defaultValue = "0") long focusTimestamp,
			@RequestParam(value = "agentId", required = false) String agentId,
			@RequestParam(value = "spanId", required = false, defaultValue = "-1") long spanId,
			@RequestParam(value = "mRpc", required = false, defaultValue = "notFound") String mRpc) {

		Map<String, Object> model = rs.getForObject("http://10.145.196.107:38080/transactionInfo.pinpoint?traceId="
				+ traceIdParam + "&agentId=" + agentId + "&spanId=" + spanId + "&focusTimestamp=" + focusTimestamp,
				Map.class);
//		System.out.println(model);

		List<List<Object>> callStack = (List<List<Object>>) model.get("callStack");

		if (CollectionUtils.isEmpty(callStack)) {
			return "";
		}
//		 System.out.println(callStack);
		// TreeNode treeNode = recursiveTree3(callStack,
		// callStack.get(0).get(6).toString(), mRpc);
		TreeNode treeNode = recursiveTree6(callStack, callStack.get(0).get(6).toString(), mRpc);
		// TreeNode treeNode = recursiveTree5(model,
		// callStack.get(0).get(6).toString(), mRpc);

		// System.out.println(treeNode);
		List<TreeNode> rsList = new ArrayList<>();
		rsList.add(treeNode);

		Map<String, Object> map = new HashMap<>();
		map.put("rsList", rsList);
		map.put("linkDataArray", ((Map<String, Object>) model.get("applicationMapData")).get("linkDataArray"));
		map.put("nodeDataArray", ((Map<String, Object>) model.get("applicationMapData")).get("nodeDataArray"));
//		String str = JSON.toJSONString(map);
		return map;
	}

	private TreeNode recursiveTree(List<List<Object>> list, String tid, String mRpc) {

		String parentId = "";
		int flag = 1;
		List<List<Object>> newList = new ArrayList<>();

		for (List<Object> cList : list) {

			if ("Tomcat Servlet Process".equals(cList.get(10).toString())) {

				if (flag != 1) {
					cList.set(7, parentId);
				}
				newList.add(cList);
				parentId = cList.get(6).toString();

				flag++;
			}

		}

		TreeNode treeNode = recursiveTree2(newList, newList.get(0).get(6).toString(), mRpc);
		// System.out.println(treeNode);

		return treeNode;
	}

	private TreeNode recursiveTree3(List<List<Object>> list, String tid, String mRpc) {

		int flag = 1;
		List<List<Object>> newList = new ArrayList<>();
		List<String> ids = new ArrayList<>();
		List<Object> parent = null;
		int parentId;
		for (List<Object> cList : list) {

			if ("Tomcat Servlet Process".equals(cList.get(10).toString())) {

				if (flag == 1) {
					ids.add(cList.get(6).toString());
					newList.add(cList);
				} else if (flag == 2) {
					ids.add(cList.get(6).toString());
					cList.set(7, ids.get(0));
					newList.add(cList);
				} else {
					parent = findParent(cList, list);
					parentId = Integer.parseInt(parent.get(7).toString());

					

					if (parentId > Integer.parseInt(ids.get(ids.size() - 1))) {
						cList.set(7, ids.get(ids.size() - 1));
						newList.add(cList);
					} else {
						cList.set(7, findParentId(parentId, ids));
						newList.add(cList);
					}

					ids.add(cList.get(6).toString());
				}

				flag++;
			}

		}

		if (newList.size() > 0) {
			TreeNode treeNode = recursiveTree4(newList, newList.get(0).get(6).toString(), mRpc);
			// System.out.println(treeNode);

			return treeNode;
		} else {
			return null;
		}

	}

	private TreeNode recursiveTree6(List<List<Object>> list, String tid, String mRpc) {

		int flag = 1;
		List<List<Object>> newList = new ArrayList<>();

		for (List<Object> cList : list) {

			if ("Tomcat Servlet Process".equals(cList.get(10).toString())) {

				if (flag == 1) {
					newList.add(cList);
					flag++;
				} else {
					String parentId = findSourceId(cList.get(7).toString(), list);

					cList.set(7, parentId);
					
					long time = findBeginTime(cList,list);
					cList.set(15, time);
					
					newList.add(cList);

				}

			}

		}
		
		

		if (newList.size() > 0) {
			TreeNode treeNode = recursiveTree4(newList, newList.get(0).get(6).toString(), mRpc);
			// System.out.println(treeNode);

			return treeNode;
		} else {
			return null;
		}

	}
	
	private long findBeginTime(List<Object> clist,List<List<Object>> lists ){
		long time= 0;
		for (List<Object> list : lists) {
			if(clist.get(7).toString().equals(list.get(6).toString())){
				long cTime = Long.parseLong(clist.get(1).toString()); 
				long fTime = Long.parseLong(list.get(1).toString()); 
				time = cTime - fTime;
			}
		}
		return time;
		
	}
	
	
	private List<Object> findObjById(String id,List<List<Object>> lists){
		List<Object> resultList = null;
		for (List<Object> list : lists) {
			if(id.equals(list.get(6).toString())){
				resultList = list;
			}
		}
		return resultList;
	}

	

	private String findSourceId(String id, List<List<Object>> callStack) {
		String findSourceId = "";

		for (List<Object> cList : callStack) {

			if (id.equals(cList.get(6).toString())) {

				if ("Tomcat Servlet Process".equals(cList.get(10).toString())) {
					String parentId = cList.get(6).toString();
					return parentId;
				} else {
					findSourceId = findSourceId(cList.get(7).toString(), callStack);
				}

			}

		}

		return findSourceId;

	}

	private String findKeyByApplicationName(String applicationName, List<List<Map>> nodeList) {
		String applicationKey = "";
		for (List<Map> list : nodeList) {
			for (Map map : list) {
				if (map.get("applicationName") == applicationName) {
					applicationKey = map.get("key").toString();
				}
			}
		}
		return applicationKey;

	}

	private String findParentApplicationNameBykey(String key, List<List<Map>> linkList, List<List<Map>> nodeList) {
		String applicationName = "";
		String from = "";
		for (List<Map> list : linkList) {
			for (Map map : list) {
				if (map.get("to") == key) {
					if (map.get("isWas").toString() == "true") {
						from = map.get("from").toString();
					}

				}
			}
		}
		for (List<Map> list : nodeList) {
			for (Map map : list) {
				if (map.get("from") == from) {
					if (map.get("isWas").toString() == "true") {
						from = map.get("from").toString();
					}

				}
			}
		}
		return applicationName;

	}

	private int findParentId(int id, List<String> ids) {

		int parentId = 0;
		for (int i = 0; i < ids.size(); i++) {
			if (id < Integer.parseInt(ids.get(i))) {
				parentId = Integer.parseInt(ids.get(i - 1));
				break;
			}

		}

		return parentId;
	}

	private List<Object> findParent(List<Object> child, List<List<Object>> list) {
		List<Object> parent = null;
		for (List<Object> list2 : list) {
			if (child.get(7).toString().equals(list2.get(6).toString())) {
				parent = list2;
			}
		}
		return parent;
	}

	private String transferLongToDate(SimpleDateFormat sdf, long millSec) {
		Date date = new Date(millSec);
		return sdf.format(date);
	}

}